<?php
declare(strict_types = 1);

namespace app\service;

use app\model\HttpLog;

/**
 * ZhdHttpService1
 * 厂家 HTTP 封装（POST form-urlencoded）
 * - 基址：http://gpsapi.zhdkj.net:20202/ZhdServiceApi.asmx
 * - 返回：厂家常见为“伪 JSON（外层 ()）”，此处转换为标准 JSON 数组/对象
 * - 坐标：厂家接口返回为百度 bd09ll（文档说明），仅在需要时调用 CoordinateService 做转换
 *
 * 幂等与缓存：
 * - 对高频轮询接口提供 5s 缓存：key = timer:{p_Wy}:{md5(规范化POST)}
 * - 规范化POST：按键名排序后 http_build_query($form, '', '&', PHP_QUERY_RFC3986)
 *
 * 错误统一：
 * - 不抛异常，返回统一 JSON 结构：['ok' => false, 'error' => 'message', 'path' => $path]
 */
class ZhdHttpService
{
    private string $base;

    public function __construct()
    {
        $this->base = rtrim(env('ZHD_BASE', 'http://gpsapi.zhdkj.net:20202/ZhdServiceApi.asmx'), '/');
    }

    /**
     * 基础 POST 调用（无缓存）
     */
    private function httpPost(string $path, array $form): array|string
    {
        $url     = $this->base . '/' . ltrim($path, '/');
        $start   = microtime(true);
        $respRaw = '';
        try {
            $options = [
                    'http' => [
                            'method'  => 'POST',
                            'header'  => "Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n",
                            'content' => http_build_query($form, '', '&', PHP_QUERY_RFC3986),
                            'timeout' => 15,
                    ],
            ];
            $context = stream_context_create($options);
            $respRaw = (string)file_get_contents($url, false, $context);
            $json    = $this->normalizeVendorJson($respRaw);
            return $json;
        } catch (\Throwable $e) {
            try {
                if ((int)env('HTTP_LOG_ENABLE', 0) === 1) {
                    HttpLog::record($url, $form, $respRaw, 0, (int)((microtime(true) - $start) * 1000), $e->getMessage());
                }
            } catch (\Throwable $e2) {
                // 忽略日志写入错误
            }
            return [
                    'ok'    => false,
                    'error' => 'HTTP 调用失败：' . $e->getMessage(),
                    'path'  => $path,
            ];
        }
    }

    /**
     * 缓存包装（默认 5s）
     */
    private function httpPostCached(string $path, array $form, int $ttl = 5): array|string
    {
        return cached_http_request(
            fn($p, $f) => $this->httpPost($p, $f),
            $path,
            $form,
            $ttl
        );
    }

    /**
     * 厂家“伪 JSON（外层 ()）”→ 标准 JSON
     */
    private function normalizeVendorJson(string|array $raw): array|string
    {
        // 兼容非字符串输入
        if (!is_string($raw)) {
            // 将非字符串（数组/对象）转换为字符串进行兜底
            $raw = json_encode($raw, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            if ($raw === null) {
                return [];
            }
        }

        // 去除 BOM 与首尾空白
        $raw = preg_replace("/^\xEF\xBB\xBF/", '', $raw ?? '');
        $raw = trim($raw ?? '');
        if ($raw === '') {
            return [];
        }

        // 仅当长度≥2且首尾为 () 才去括号
        if (strlen($raw) >= 2 && $raw[0] === '(' && substr($raw, -1) === ')') {
            $raw = substr($raw, 1, -1);
        }

        // 尝试解析为 JSON
        $j = json_decode($raw, true);
        if (json_last_error() === JSON_ERROR_NONE) {
            return $j;
        }

        // 某些接口返回纯 true/false/数字或其他文本，直接回退为原始字符串
        return $raw;
    }

    // 以下为全部接口一一实现（名称 = 路径）
    public function FunDengLu(array $p): array|string
    {
        // 按最新文档补全必填字段的默认值
        $p['z2']  = $p['z2'] ? $p['z2'] : env('ZHD_USER','13523033229');             // 登录名 
        $p['z3']  = $p['z3'] ? $p['z3'] : env('ZHD_PWD','123456');                  // 密码
        $p['z4']  = isset($p['z4']) ? $p['z4'] : 0;  // 版本号 默认0
        $p['z5']  = $p['z5'] ?? '';                  // 预留 默认""
        $p['z6']  = $p['z6'] ?? '';                  // 预留 默认""
        $p['z7']  = $p['z7'] ?? '';                  // 预留 默认""
        $p['z8']  = $p['z8'] ?? '';                  // 预留 默认""
        $p['z9']  = isset($p['z9']) ? $p['z9'] : 4;  // 平台登录类型 默认4
        $p['z10'] = $p['z10'] ?? '';                 // 预留 默认""
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunBaoChi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunDwGetZu(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunDwGetChe(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunDwGetCheXinXi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetCheState(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetCheStateEx(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    // 高频轮询接口采用 5s 缓存
    public function FunDwGetOne(array $p): array|string
    {
        return $this->httpPostCached(__FUNCTION__, $p);
    }

    public function FunDwGetDwTimer(array $p): array|string
    {
        return $this->httpPostCached(__FUNCTION__, $p);
    }

    public function FunDwGetDwTimerEx(array $p): array|string
    {
        return $this->httpPostCached(__FUNCTION__, $p);
    }

    public function FunDwGetOneListAPI(array $p): array|string
    {
        return $this->httpPostCached(__FUNCTION__, $p);
    }

    public function FunDwNotSel(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunClear(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunLiChengLists(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunHuiFang(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunZuiHou(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunZhuangTaiTongJi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunLxtj(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunAddDiLiWeiLanApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunDeleteWeiLanApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetWLInfoApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetOneWeiLanApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunAddWeiLanSheBeiApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunEditWeiLanSheBeiApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunDeleteSheBeiWeiLanApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetSbInfosApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetGlInfosApi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetLock(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunReLock(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunGetOBDInfos(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunSelectBaoJingChuLi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunSelectBaoJingJiLu(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunZdscsj(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunZdscsjEx(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunZlChaXun(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunZttj(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunTjGetChe(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunLxGetChe(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunDwGetDiZhi(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunEdGetZu(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }

    public function FunEdSaveApiEx(array $p): array|string
    {
        return $this->httpPost(__FUNCTION__, $p);
    }
}
